import os
import random
import string
import logging
import paramiko
from django.conf import settings
from django.utils import timezone
from hosts.models import Host, HostPassword
from cryptography.fernet import Fernet
import base64

logger = logging.getLogger(__name__)


class PasswordManager:
    """密码管理器"""
    
    def __init__(self):
        self.ssh_timeout = 30
        self.ssh_retries = 3
    
    def generate_strong_password(self, length=16):
        """生成强密码"""
        # 确保包含至少一个大写字母、小写字母、数字和特殊字符
        lowercase = string.ascii_lowercase
        uppercase = string.ascii_uppercase
        digits = string.digits
        symbols = "!@#$%^&*"
        
        # 每种类型至少一个字符
        password = [
            random.choice(lowercase),
            random.choice(uppercase),
            random.choice(digits),
            random.choice(symbols)
        ]
        
        # 填充剩余长度
        remaining_length = length - 4
        all_chars = lowercase + uppercase + digits + symbols
        password.extend(random.choice(all_chars) for _ in range(remaining_length))
        
        # 打乱密码
        random.shuffle(password)
        return ''.join(password)
    
    def change_host_password(self, host, new_password=None):
        """修改主机密码"""
        try:
            if not new_password:
                new_password = self.generate_strong_password()
            
            # 获取当前密码
            try:
                host_password = HostPassword.objects.get(host=host)
                current_password = host_password.get_password()
            except HostPassword.DoesNotExist:
                # 如果不存在密码记录，创建一个
                host_password = HostPassword.objects.create(host=host)
                current_password = None
            
            # 尝试通过SSH修改密码
            if self.change_password_via_ssh(host, current_password, new_password):
                # 更新数据库中的密码
                host_password.set_password(new_password)
                logger.info(f"主机 {host.hostname} 密码修改成功")
                return True, new_password
            else:
                logger.error(f"主机 {host.hostname} SSH密码修改失败")
                return False, None
                
        except Exception as e:
            logger.error(f"修改主机 {host.hostname} 密码时发生错误: {str(e)}")
            return False, None
    
    def change_password_via_ssh(self, host, current_password, new_password):
        """通过SSH修改密码"""
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        
        try:
            # 尝试连接
            ssh.connect(
                hostname=host.ip_address,
                username='root',
                password=current_password,
                timeout=self.ssh_timeout
            )
            
            # 修改密码
            if host.os_type == 'linux':
                return self._change_linux_password(ssh, new_password)
            elif host.os_type == 'windows':
                return self._change_windows_password(ssh, new_password)
            else:
                logger.warning(f"不支持的操作系统类型: {host.os_type}")
                return False
                
        except paramiko.AuthenticationException:
            logger.error(f"主机 {host.hostname} SSH认证失败")
            return False
        except paramiko.SSHException as e:
            logger.error(f"主机 {host.hostname} SSH连接异常: {str(e)}")
            return False
        except Exception as e:
            logger.error(f"主机 {host.hostname} 连接失败: {str(e)}")
            return False
        finally:
            ssh.close()
    
    def _change_linux_password(self, ssh, new_password):
        """修改Linux系统密码"""
        try:
            # 使用chpasswd命令修改密码
            command = f"echo 'root:{new_password}' | chpasswd"
            stdin, stdout, stderr = ssh.exec_command(command)
            
            # 检查命令执行结果
            exit_status = stdout.channel.recv_exit_status()
            if exit_status == 0:
                logger.info("Linux密码修改成功")
                return True
            else:
                error = stderr.read().decode().strip()
                logger.error(f"Linux密码修改失败: {error}")
                return False
                
        except Exception as e:
            logger.error(f"Linux密码修改异常: {str(e)}")
            return False
    
    def _change_windows_password(self, ssh, new_password):
        """修改Windows系统密码"""
        try:
            # 使用net user命令修改密码
            command = f"net user administrator {new_password}"
            stdin, stdout, stderr = ssh.exec_command(command)
            
            # 检查命令执行结果
            exit_status = stdout.channel.recv_exit_status()
            if exit_status == 0:
                logger.info("Windows密码修改成功")
                return True
            else:
                error = stderr.read().decode().strip()
                logger.error(f"Windows密码修改失败: {error}")
                return False
                
        except Exception as e:
            logger.error(f"Windows密码修改异常: {str(e)}")
            return False
    
    def test_ssh_connection(self, host, password):
        """测试SSH连接"""
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        
        try:
            ssh.connect(
                hostname=host.ip_address,
                username='root',
                password=password,
                timeout=self.ssh_timeout
            )
            
            # 执行简单命令测试连接
            stdin, stdout, stderr = ssh.exec_command('echo "SSH连接测试成功"')
            exit_status = stdout.channel.recv_exit_status()
            
            if exit_status == 0:
                logger.info(f"主机 {host.hostname} SSH连接测试成功")
                return True
            else:
                logger.error(f"主机 {host.hostname} SSH命令执行失败")
                return False
                
        except Exception as e:
            logger.error(f"主机 {host.hostname} SSH连接测试失败: {str(e)}")
            return False
        finally:
            ssh.close()
    
    def get_password_status(self, host):
        """获取密码状态信息"""
        try:
            host_password = HostPassword.objects.get(host=host)
            return {
                'hostname': host.hostname,
                'ip_address': host.ip_address,
                'password_age_hours': host_password.get_password_age(),
                'next_change_time': host_password.next_change_time,
                'is_expired': host_password.is_password_expired(),
                'last_changed': host_password.password_changed_at,
                'history_count': len(host_password.password_history)
            }
        except HostPassword.DoesNotExist:
            return {
                'hostname': host.hostname,
                'ip_address': host.ip_address,
                'password_age_hours': None,
                'next_change_time': None,
                'is_expired': True,
                'last_changed': None,
                'history_count': 0
            }


class BulkPasswordManager:
    """批量密码管理器"""
    
    def __init__(self):
        self.password_manager = PasswordManager()
    
    def change_all_expired_passwords(self):
        """修改所有过期的密码"""
        try:
            # 获取所有过期的密码
            expired_passwords = HostPassword.objects.filter(
                next_change_time__lte=timezone.now()
            )
            
            if not expired_passwords.exists():
                logger.info("没有需要更新的过期密码")
                return {"success": 0, "failed": 0, "total": 0}
            
            success_count = 0
            failed_count = 0
            
            for host_password in expired_passwords:
                try:
                    success, new_password = self.password_manager.change_host_password(
                        host_password.host
                    )
                    if success:
                        success_count += 1
                        logger.info(f"主机 {host_password.host.hostname} 密码更新成功")
                    else:
                        failed_count += 1
                        logger.error(f"主机 {host_password.host.hostname} 密码更新失败")
                        
                except Exception as e:
                    failed_count += 1
                    logger.error(f"主机 {host_password.host.hostname} 密码更新异常: {str(e)}")
            
            total = success_count + failed_count
            logger.info(f"批量密码更新完成: 成功 {success_count}, 失败 {failed_count}, 总计 {total}")
            
            return {
                "success": success_count,
                "failed": failed_count,
                "total": total
            }
            
        except Exception as e:
            logger.error(f"批量密码更新任务执行失败: {str(e)}")
            raise
    
    def change_passwords_by_hosts(self, host_ids):
        """根据主机ID列表修改密码"""
        try:
            hosts = Host.objects.filter(id__in=host_ids)
            success_count = 0
            failed_count = 0
            
            for host in hosts:
                try:
                    success, new_password = self.password_manager.change_host_password(host)
                    if success:
                        success_count += 1
                        logger.info(f"主机 {host.hostname} 密码更新成功")
                    else:
                        failed_count += 1
                        logger.error(f"主机 {host.hostname} 密码更新失败")
                        
                except Exception as e:
                    failed_count += 1
                    logger.error(f"主机 {host.hostname} 密码更新异常: {str(e)}")
            
            total = success_count + failed_count
            logger.info(f"指定主机密码更新完成: 成功 {success_count}, 失败 {failed_count}, 总计 {total}")
            
            return {
                "success": success_count,
                "failed": failed_count,
                "total": total
            }
            
        except Exception as e:
            logger.error(f"指定主机密码更新任务执行失败: {str(e)}")
            raise
